using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using ADODB;
using System.Reflection;
using System.Collections;
using System.IO;
using System.Xml;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using Microsoft.CommerceServer.Runtime;
using Microsoft.CommerceServer.Runtime.Orders;

using Microsoft.CommerceServer.Interop.Configuration;
using System.Data.OleDb;

namespace CS2007OrderFormViewer
{
    public partial class OrderFormViewer : Form
    {
        private GlobalConfig2FreeThreaded oglbConfig = new GlobalConfig2FreeThreaded();
        private SiteConfigReadOnlyFreeThreaded oSiteConfig = new SiteConfigReadOnlyFreeThreaded();
        private Recordset oRstSites = new ADODB.RecordsetClass();
        
        public OrderFormViewer()
        {
            InitializeComponent();
        }

        private DataSet DoSearch(bool defaultSearch)
        {
            string sqlStr = null;

            if (defaultSearch)
            {
                sqlStr = "Select top 10 * from " + cmbTables.Text;
            }
            else
            {
                sqlStr = "Select * from " + cmbTables.Text + " where " + cmbColumns.Text + "='" + txtWhereValue.Text + "'";
            }
            // clean the connection string
            OleDbConnectionStringBuilder builder1 = new OleDbConnectionStringBuilder(getTransactionConStr(cmbCommerceSites.Text));
            builder1.Remove("Provider");

            SqlDataAdapter search = new SqlDataAdapter(sqlStr, builder1.ConnectionString);
            DataSet dsSearch = new DataSet();

            search.Fill(dsSearch, cmbTables.Text);

            return dsSearch;

        }

        private void GetTables(string siteName)
        {
            cmbTables.Items.Clear();

            string sqlStr = "SELECT DISTINCT sysobjects.name " +
                            "FROM sysobjects INNER JOIN " +
                            "syscolumns ON sysobjects.id = syscolumns.id " +
                            "WHERE (sysobjects.xtype = 'U') AND (syscolumns.name = N'marshaled_data' or syscolumns.name = 'MarshalledData')";
            SqlConnection Con = getSQLConnection(getTransactionConStr(siteName));

            Con.Open();

            SqlCommand cmd = new SqlCommand(sqlStr, Con);

            cmd.CommandType = CommandType.Text;
            SqlDataReader Drtbls = cmd.ExecuteReader();

            while (Drtbls.Read())
            {
                cmbTables.Items.Add(Drtbls.GetValue(0));
            }

            cmbTables.SelectedIndex = 0;

            Drtbls.Close();
            Con.Close();
        }

        private void GetColumns(string siteName)
        {
            cmbColumns.Items.Clear();
            string sqlStr = "SELECT syscolumns.name as Column_Names, systypes.name as Type_Name " +
                            "FROM sysobjects INNER JOIN " +
                            " syscolumns ON sysobjects.id = syscolumns.id INNER JOIN " +
                            " systypes ON syscolumns.xtype = systypes.xtype " +
                            " WHERE sysobjects.name = '" + cmbTables.Text + "'";
            SqlConnection Con = getSQLConnection(getTransactionConStr(siteName));

            Con.Open();

            SqlCommand cmd = new SqlCommand(sqlStr, Con);

            cmd.CommandType = CommandType.Text;
            SqlDataReader Drcolmns = cmd.ExecuteReader();

            while (Drcolmns.Read())
            {
                cmbColumns.Items.Add(Drcolmns.GetValue(0));
            }

            cmbColumns.SelectedIndex = 0;

            Drcolmns.Close();
            Con.Close();
        }

        private SqlConnection getSQLConnection(string connectionStr)
        {
            // clean the connection string
            OleDbConnectionStringBuilder builder1 = new OleDbConnectionStringBuilder(connectionStr);
            builder1.Remove("Provider");

            // get the orders resource 
            // and extract connection string
            // to contruct a SQL Connection
            SqlConnection sqlCon = new SqlConnection();
            sqlCon.ConnectionString = builder1.ConnectionString;

            return sqlCon;
        }

        private string getTransactionConStr(string siteName)
        {
            oSiteConfig.Initialize(siteName);

            foreach (Field fld in oSiteConfig.Fields)
            {
                Recordset rst = fld.Value as Recordset;
				// if we got a recordset then find out it we have a database
                if (rst != null)
                {
                    foreach (Field f in rst.Fields)
                    {
                        if (f.Name == "connstr_db_Transactions")
                        {
                            return f.Value.ToString();
                        }
                    }
                }
            }

            return null;
        }

        private Recordset getCommerceSites()
        {
            // initialize the Global Config object
            oglbConfig.Initialize(null);

            // get all sites
            return (RecordsetClass)oglbConfig.Sites();
        }

        private void OrderFormViewer_Load(object sender, EventArgs e)
        {
            // get a list of sites
            try
            {
                oRstSites = getCommerceSites();

                // clear the combobox
                cmbCommerceSites.Items.Clear();

                // display Commerce Sites
                while (!oRstSites.EOF)
                {
                    // iterate and get all Commerce Sites
                    foreach (Field fld in oRstSites.Fields)
                    {
                        cmbCommerceSites.Items.Add(fld.Name);
                    }
                    oRstSites.MoveNext();
                }
                // move to the first index and disply the first site
                cmbCommerceSites.SelectedIndex = 0;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void cmbCommerceSites_SelectedIndexChanged(object sender, EventArgs e)
        {
            tvwOrderForm.Nodes.Clear();

            // as the index changes show transaction tables
            GetTables(cmbCommerceSites.Text);
        }

        private void cmbTables_SelectedIndexChanged(object sender, EventArgs e)
        {
            tvwOrderForm.Nodes.Clear();
            GetColumns(cmbCommerceSites.Text);
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            // clear the nodes
            tvwOrderForm.Nodes.Clear();

            // do a search based on values entered
            if (txtWhereValue.Text != string.Empty)
            {
                // perforam search
                dgvwOrders.DataSource = DoSearch(false).Tables[0];
            }
            else
            {
                // default search
                dgvwOrders.DataSource = DoSearch(true).Tables[0];
            }
        }

        private void dgvwOrders_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {

        }

        private void dgvwOrders_MouseDown(object sender, MouseEventArgs e)
        {
            DataGridView myGrid = (DataGridView)sender;
            System.Windows.Forms.DataGridView.HitTestInfo hti;
            hti = myGrid.HitTest(e.X, e.Y);

            if (hti.Type == DataGridViewHitTestType.RowHeader)
            {
                // clear our tree
                tvwOrderForm.Nodes.Clear();

                // either get weakly type data or basket
                if (0 == cmbColumns.Items.IndexOf("MarshalledData"))
                {
                    callDisplayTenderManagerDict((DataTable)(myGrid.DataSource), "WeaklyTypedProperty", hti.RowIndex, "MarshalledData");
                }
                if (0 == cmbColumns.Items.IndexOf("marshaled_data"))
                {
                    callDisplayTenderManagerDict((DataTable)(myGrid.DataSource), "SavedBaskets", hti.RowIndex, "marshaled_data");
                }                
            }
        }

        private void callDisplayTenderManagerDict(DataTable dataSource, string nodeName, int rowIndex, string marshalledColumn)
        {
            byte[] binaryData = (byte[])dataSource.Rows[rowIndex][marshalledColumn];
            TreeNode tn = tvwOrderForm.Nodes.Add(nodeName);

            DisplayTenderManagerDict("", getSQLBinaryData(binaryData), tn, null);
        }

        private object getSQLBinaryData(byte[] binaryData)
        {
            System.IO.Stream stream1 = new MemoryStream(binaryData, false);
            IFormatter formatter = new BinaryFormatter();
            OrderContext orderContext = OrderContext.Create(cmbCommerceSites.Text);

            Type orderType = orderContext.GetType();
            PropertyInfo orderConfigPropertyInfo = orderType.GetProperty("OrdersConfiguration", BindingFlags.Instance | BindingFlags.NonPublic);
            object obj = orderConfigPropertyInfo.GetValue(orderContext, null);
            PropertyInfo orderConfigPropertyInfo2 = obj.GetType().GetProperty("OrdersClassSerializationBinder", BindingFlags.Instance | BindingFlags.NonPublic);

            formatter.Binder = (SerializationBinder)orderConfigPropertyInfo2.GetValue(obj, null);

            return formatter.Deserialize(stream1);
        }

        private void DisplayTenderManagerDict(string pKey, object pValue, TreeNode node, Basket baseBasket)
        {
            // dont forget to code for ArrayList

            // Get the type we are dealing with
            Basket basket = baseBasket;

            switch (pValue.GetType().Name)
            {
                case "WeaklyTypedPropertyDictionary":
                    WeaklyTypedPropertyDictionary weakprop = (WeaklyTypedPropertyDictionary)pValue;
                    foreach (DictionaryEntry dictEntry in weakprop)
                    {
                        switch (dictEntry.Value.GetType().Name)
                        {
                            case "ArrayList":
                                TreeNode arrayNode = node.Nodes.Add(dictEntry.Key + "=" + dictEntry.Value.ToString());

                                DisplayTenderManagerDict("", dictEntry.Value, arrayNode , null);

                                break;
                            case "DictionaryClass":
                                TreeNode dictNode = node.Nodes.Add(dictEntry.Key + "=" + dictEntry.Value.ToString());

                                DisplayTenderManagerDict("", dictEntry.Value, dictNode, null);
                                break;
                            case"PromoCodeStringCollection":
                                TreeNode promodNode = node.Nodes.Add(dictEntry.Key + "=" + dictEntry.Value.ToString());

                                DisplayTenderManagerDict("", dictEntry.Value, promodNode, null);
                                break;
                            default:
                                node.Nodes.Add(dictEntry.Key + "=" + dictEntry.Value.ToString());
                                break;
                        }
                    }
                    break;
                case "Basket":
                    basket = (Basket)pValue;
                    PropertyInfo[] propertyInfo = basket.GetType().GetProperties();

                    for (int i = 0; i < propertyInfo.Length; i++)
                    {
                        switch (propertyInfo[i].Name)
                        {
                            case "Item":
                                break;
                            case "OrderForms":
                                OrderFormCollection orderforms = (OrderFormCollection)propertyInfo[i].GetValue(basket, null);
                                DisplayTenderManagerDict("", orderforms, node, basket);
                                break;
                            case "Addresses":
                                OrderAddressCollection orderAddress = (OrderAddressCollection)propertyInfo[i].GetValue(basket, null);
                                DisplayTenderManagerDict("", orderAddress, node, basket);
                                break;
                            default:
                                node.Nodes.Add(propertyInfo[i].Name + "=" + propertyInfo[i].GetValue(basket, null));
                                break;
                        }
                    }
                    break;
                case "ArrayList":
                    ArrayList arrayList = (ArrayList)pValue;
                    TreeNode nodearrayList = node.Nodes.Add(arrayList.GetType().Name);

                    for (int r = 0; arrayList.Count > r; r++ )
                    {
                        nodearrayList.Nodes.Add(r.ToString() + "=" + arrayList[r].ToString());
                    }
                    break;
                case "OrderFormCollection":
                    OrderFormCollection orderforms2 = (OrderFormCollection)pValue;
                    TreeNode nodeofs = node.Nodes.Add(orderforms2.GetType().Name);

                    foreach (OrderForm of in orderforms2)
                    {
                        TreeNode nodeof = nodeofs.Nodes.Add(of.GetType().Name);

                        PropertyInfo[] myPropertyInfoOF = of.GetType().GetProperties();
                        for (int j = 0; j < myPropertyInfoOF.Length; j++)
                        {
                            switch(myPropertyInfoOF[j].Name)
                            {
                                case "Item":
                                    break;
                                case "Payments":
                                    PaymentCollection payments = (PaymentCollection)myPropertyInfoOF[j].GetValue(of, null);
                                    DisplayTenderManagerDict("", payments, nodeof, baseBasket);
                                    break;
                                case "LineItems":
                                    LineItemCollection lineitems = (LineItemCollection)myPropertyInfoOF[j].GetValue(of, null);
                                    DisplayTenderManagerDict("", lineitems, nodeof, baseBasket);
                                    break;
                                case "PromoCodeRecords":
                                    PromoCodeRecordCollection promoCodeRecords = (PromoCodeRecordCollection)myPropertyInfoOF[j].GetValue(of, null);
                                    DisplayTenderManagerDict("", promoCodeRecords, nodeof, baseBasket);
                                    break;
                                case "PromoCodes":
                                    PromoCodeStringCollection promoCodes = (PromoCodeStringCollection)myPropertyInfoOF[j].GetValue(of, null);
                                    DisplayTenderManagerDict("", promoCodes, nodeof, baseBasket);
                                    break;
                                case "Shipments":
                                    ShipmentCollection shipments = (ShipmentCollection)myPropertyInfoOF[j].GetValue(of, null);
                                    DisplayTenderManagerDict("", shipments, nodeof, baseBasket);
                                    break;
                                default:
                                    nodeof.Nodes.Add(myPropertyInfoOF[j].Name + "=" + myPropertyInfoOF[j].GetValue(of, null));
                                    break;
                            }
                        }
                    }
                    break;
                case "PaymentCollection":
                    PaymentCollection payments2 = (PaymentCollection)pValue;
                    TreeNode nodepayments = node.Nodes.Add(payments2.GetType().Name);

                    foreach (Payment payment in payments2)
                    {
                        TreeNode nodepayment = nodepayments.Nodes.Add(payment.GetType().Name);
                        PropertyInfo[] propertyInfopayment = payment.GetType().GetProperties();
                        for (int m = 0; m < propertyInfopayment.Length; m++)
                        {
                            if (propertyInfopayment[m].Name != "Item")
                            {
                                nodepayment.Nodes.Add(propertyInfopayment[m].Name + "=" + propertyInfopayment[m].GetValue(payment, null));
                            }
                        }
                    }
                    break;
                case "LineItemCollection":
                    LineItemCollection lineitems2 = (LineItemCollection)pValue;
                    TreeNode nodeitems = node.Nodes.Add(lineitems2.GetType().Name);

                    foreach (LineItem item in lineitems2)
                    {
                        TreeNode nodeitem = nodeitems.Nodes.Add(item.GetType().Name);

                        PropertyInfo[] propertyInfoitem = item.GetType().GetProperties();
                        for (int l = 0; l < propertyInfoitem.Length; l++)
                        {
                            switch(propertyInfoitem[l].Name)
                            {
                                case "Item":
                                    break;
                                case "OrderLevelDiscountsApplied":
                                    DiscountApplicationRecordCollection orderLevelDiscountsApplied = (DiscountApplicationRecordCollection)propertyInfoitem[l].GetValue(item, null);
                                    DisplayTenderManagerDict("", orderLevelDiscountsApplied, nodeitem, baseBasket);
                                    break;
                                case "ItemLevelDiscountsApplied":
                                    DiscountApplicationRecordCollection itemLevelDiscountsApplied = (DiscountApplicationRecordCollection)propertyInfoitem[l].GetValue(item, null);
                                    DisplayTenderManagerDict("", itemLevelDiscountsApplied, nodeitem, baseBasket);
                                    break;
                                default:
                                    nodeitem.Nodes.Add(propertyInfoitem[l].Name + "=" + propertyInfoitem[l].GetValue(item, null));
                                    break;
                            }                            
                        }
                    }
                    break;
                case "DiscountApplicationRecordCollection":
                    DiscountApplicationRecordCollection discountApplicationRecords = (DiscountApplicationRecordCollection)pValue;
                    TreeNode nodeiscountApplicationRecords = node.Nodes.Add(discountApplicationRecords.GetType().Name);
                    foreach (DiscountApplicationRecord discountApplicationRecord in discountApplicationRecords)
                    {
                        TreeNode nodeiscountApplicationRecord = nodeiscountApplicationRecords.Nodes.Add(discountApplicationRecord.GetType().Name);
                        PropertyInfo[] propertyInfodiscountApplicationRecord = discountApplicationRecord.GetType().GetProperties();
                        for (int p = 0; p < propertyInfodiscountApplicationRecord.Length; p++)
                        {
                            if (propertyInfodiscountApplicationRecord[p].Name != "Item")
                            {
                                nodeiscountApplicationRecord.Nodes.Add(propertyInfodiscountApplicationRecord[p].Name + "=" + propertyInfodiscountApplicationRecord[p].GetValue(discountApplicationRecord, null));
                            }
                        }
                    }
                    break;
                case "PromoCodeRecordCollection":
                    PromoCodeRecordCollection PromoCodeRecords = (PromoCodeRecordCollection)pValue;
                    TreeNode nodepromoCodeRecords = node.Nodes.Add(PromoCodeRecords.GetType().Name);
                    foreach (PromoCodeRecord promoCodeRecord in PromoCodeRecords)
                    {
                        TreeNode nodepromoCodeRecord = nodepromoCodeRecords.Nodes.Add(promoCodeRecord.GetType().Name);
                        PropertyInfo[] propertyInfopromoCodeRecord = promoCodeRecord.GetType().GetProperties();
                        for (int n = 0; n < propertyInfopromoCodeRecord.Length; n++)
                        {
                            if (propertyInfopromoCodeRecord[n].Name != "Item")
                            {
                                nodepromoCodeRecord.Nodes.Add(propertyInfopromoCodeRecord[n].Name + "=" + propertyInfopromoCodeRecord[n].GetValue(promoCodeRecord, null));
                            }
                        }
                    }
                    break;
                case "ShipmentCollection":
                    ShipmentCollection shipments2 = (ShipmentCollection)pValue;
                    TreeNode nodeshipments = node.Nodes.Add(shipments2.GetType().Name);

                    foreach (Shipment shipment in shipments2)
                    {
                        TreeNode nodeshipment = nodeshipments.Nodes.Add(shipment.GetType().Name);
                        PropertyInfo[] propertyInfonodeshipment = shipment.GetType().GetProperties();
                        for (int o = 0; o < propertyInfonodeshipment.Length; o++)
                        {
                            switch (propertyInfonodeshipment[o].Name)
                            {
                                case "Item":
                                    break;
                                case "ShippingDiscounts":
                                    ShippingDiscountCollection shippingcol = (ShippingDiscountCollection)propertyInfonodeshipment[o].GetValue(shipment, null);
                                    DisplayTenderManagerDict("", shippingcol, nodeshipment, baseBasket);
                                    break;
                                default:
                                    nodeshipment.Nodes.Add(propertyInfonodeshipment[o].Name + "=" + propertyInfonodeshipment[o].GetValue(shipment, null));
                                    break;
                            }
                        }
                    }
                    break;
                case "ShippingDiscountCollection":
                    ShippingDiscountCollection shippingDiscountCollection = (ShippingDiscountCollection)pValue;
                    TreeNode nodeshippingDiscountCollection = node.Nodes.Add(shippingDiscountCollection.GetType().Name);

                    foreach (ShippingDiscountRecord shippingDiscount in shippingDiscountCollection)
                    {
                        TreeNode nodeshippingDiscount = nodeshippingDiscountCollection.Nodes.Add(shippingDiscount.GetType().Name);
                        PropertyInfo[] propertyInfoshippingDiscount = shippingDiscount.GetType().GetProperties();
                        for (int q = 0; q < propertyInfoshippingDiscount.Length; q++)
                        {
                            if (propertyInfoshippingDiscount[q].Name != "Item")
                            {
                                nodeshippingDiscount.Nodes.Add(propertyInfoshippingDiscount[q].Name + "=" + propertyInfoshippingDiscount[q].GetValue(shippingDiscount, null));
                            }
                        }
                    }
                    break;
                case "OrderAddressCollection":
                    OrderAddressCollection orderAddresses2 = (OrderAddressCollection)pValue;
                    TreeNode nodeAddresses = node.Nodes.Add(orderAddresses2.GetType().Name);

                    foreach (OrderAddress address in orderAddresses2)
                    {
                        TreeNode nodeAddress = nodeAddresses.Nodes.Add(address.GetType().Name);
                        PropertyInfo[] propertyInfoAddress = address.GetType().GetProperties();
                        for (int k = 0; k < propertyInfoAddress.Length; k++)
                        {
                            if (propertyInfoAddress[k].Name != "Item")
                            {
                                nodeAddress.Nodes.Add(propertyInfoAddress[k].Name + "=" + propertyInfoAddress[k].GetValue(address, null));
                            }
                        }
                    }
                    break;
                case "RuntimePropertyInfo":
                    PropertyInfo prop = (PropertyInfo)pValue;
                    TreeNode tnItem = node.Nodes.Add(prop.DeclaringType.Name);
                    PropertyInfo[] propertyInfo2 = prop.DeclaringType.GetProperties();

                    for (int j = 0; j < propertyInfo2.Length; j++)
                    {
                        if (propertyInfo2[j].Name != "Item")
                        {
                            switch (propertyInfo2[j].Name)
                            {
                                case "":
                                    break;
                                default:
                                    tnItem.Nodes.Add(propertyInfo2[j].Name + "=" + propertyInfo2[j].GetValue(baseBasket, null));
                                    break;
                            }
                        }
                    }
                    break;
                case "DictionaryClass":
                    DictionaryClass dictClass = (DictionaryClass)pValue;

                    foreach (string dict in dictClass)
                    {
                        node.Nodes.Add(dict + "=" + dictClass[dict].ToString());
                    }
                    break;
                case "PromoCodeStringCollection":
                    PromoCodeStringCollection promoCodeStrings = (PromoCodeStringCollection)pValue;
                    
                    for (int promoCode = 0; promoCodeStrings.Count > promoCode; promoCode++)
                    {
                        node.Nodes.Add(promoCode + "=" + promoCodeStrings[promoCode].ToString());
                    }
                    break;
            }
        }
    }
}